﻿using System;
using System.Globalization;
using System.IO;
using System.Text;
using Resolve.Contracts;
using Resolve.FlagInfo;

namespace Resolve.Core
{
    /// <summary>
    /// 查找标志
    /// </summary>
    public class FlagFinderFromFile : IFlagFinder
    {
        /// <summary>
        /// 文件路径或者字符串内容
        /// </summary>
        public string Source { private get; set; }



        //private Stream _streamFile;

        private StreamReader _streamReaderFile;

        /// <summary>
        /// 查找标志
        /// </summary>
        public FlagCodeInFile FindFlags()
        {
            Encoding encoding = GetFileEncoding(Source);
            InitStreamReader(encoding);
            int iLast = -1;//上一个字符
            int iPosition = 0;//字符位置
            int iFlagStart = 0;//标志开始位置
            int iFlagEnd = 0;//标志结束位置
            bool bFindFlag = false;//是否找到标志
            bool bFindFlagInBody = false;//在语句体中
            bool bProperty = false;//属性
            bool bFunc = false;//方法
            bool bBody = false;//语句体
            bool bSure = false;//是否确定标志类型
            int iSmallLevel = 0;//小括号层次数
            int iBigLevel = 0;//大括号层次数
            bool bIntoDouble = false;//是否进入双引号 
            FlagCodeInFile flagCodeInFile = new FlagCodeInFile(0, Source, string.Empty);
            if (encoding.Equals(Encoding.Default))
            {
                flagCodeInFile.EncodingStyle = EncodingStyle.Default;
            }
            else if (encoding.Equals(Encoding.UTF8))
            {
                flagCodeInFile.EncodingStyle = EncodingStyle.Utf8;
            }
            else if (encoding.Equals(Encoding.BigEndianUnicode))
            {
                flagCodeInFile.EncodingStyle = EncodingStyle.BigEndianUnicode;
            }
            else if (encoding.Equals(Encoding.Unicode))
            {
                flagCodeInFile.EncodingStyle = EncodingStyle.Unicode;
            }
            else
            {
                flagCodeInFile.EncodingStyle = EncodingStyle.Gb2312;
            }
            try
            {
                FlagCode flagCode = new FlagCode();
                StringBuilder sb = new StringBuilder();
                const int dataLenght = 1024;
                char[] data = new char[dataLenght];
                int iLenght;
                do
                {
                    iLenght = ReadNext(data);
                    foreach (int iCurrent in data)
                    {
                        //找到标志
                        if (iCurrent == ResolveConfig.Flag && !bFindFlag && iSmallLevel == 0 && iBigLevel == 0)
                        {
                            bFindFlag = true;
                            bProperty = true;
                            iFlagStart = iPosition;
                        }
                        else if (iCurrent == ResolveConfig.Flag && iLast == ResolveConfig.Flag && bFindFlag &&
                                 !bIntoDouble && iSmallLevel == 0 && iBigLevel == 0) //找到@@，标志无效
                        {
                            bFindFlag = false;
                            bProperty = false;
                            iFlagEnd = iPosition;
                            flagCode.Code = ((char)ResolveConfig.Flag).ToString(CultureInfo.InvariantCulture) +
                                            (char)iCurrent;
                            flagCode.Start = iFlagStart;
                            flagCode.End = iFlagEnd;
                            flagCode.FlagStyle = FlagStyle.FlagEscape;
                            flagCodeInFile.AddCode(flagCode);
                            flagCode = new FlagCode();
                            iFlagStart = 0;
                            iFlagEnd = 0;
                            sb.Remove(sb.Length - 1, 1);
                        }
                        //找到标志
                        if (bFindFlag)
                        {
                            sb.Append(((char)iCurrent).ToString(CultureInfo.InvariantCulture));
                            //sb.Append(encoding.GetString(new byte[] { iCurrent }));
                            //属性处理
                            if (bProperty && bFunc == false && bBody == false)
                            {
                                switch (iCurrent)
                                {
                                    case 40: //(
                                        bProperty = false;
                                        bFunc = true;
                                        iSmallLevel = 1;
                                        break;
                                    case 32: //空格
                                        bSure = true;
                                        flagCode.FlagStyle = FlagStyle.Property;
                                        iFlagEnd = iPosition; //把空格也算进去
                                        sb.Remove(sb.Length - 1, 1); //去掉空格
                                        break;
                                    default:
                                        if (iLast == 13 && iCurrent == 10) //回车
                                        {
                                            bSure = true;
                                            flagCode.FlagStyle = FlagStyle.Property;
                                            iFlagEnd = iPosition - 2; //回车不算进去
                                            sb.Remove(sb.Length - 2, 2); //去掉\r\n(回车)
                                        }
                                        else if (iCurrent == 123) //{
                                        {
                                            bProperty = false;
                                            bBody = true;
                                            iSmallLevel = 0;
                                            iBigLevel = 1;
                                        }
                                        break;
                                }
                            }
                            else if (!bProperty && bFunc) //方法处理
                            {
                                if (iCurrent == 34 && !bIntoDouble) //("
                                {
                                    bIntoDouble = true;
                                }
                                else if (iCurrent == 34 && iLast != 92 && bIntoDouble) //\")
                                {
                                    bIntoDouble = false;
                                }
                                else if (iCurrent == 40 && !bIntoDouble) //(
                                {
                                    iSmallLevel++;
                                }
                                else if (iCurrent == 41 && !bIntoDouble) //)
                                {
                                    iSmallLevel--;
                                }
                                else if (iCurrent == 123) //{
                                {
                                    bFunc = false;
                                    bBody = true;
                                    bIntoDouble = false;
                                    iBigLevel = 1;
                                }
                                else if (iCurrent == 32 && !bIntoDouble && iSmallLevel == 0) //空格
                                {
                                    bSure = true;
                                    flagCode.FlagStyle = FlagStyle.Func;
                                    iFlagEnd = iPosition;
                                    sb.Remove(sb.Length - 1, 1); //去掉空格
                                }
                                else if (iLast == 13 && iCurrent == 10) //回车
                                {
                                    bSure = true;
                                    flagCode.FlagStyle = FlagStyle.Func;
                                    iFlagEnd = iPosition - 2; //回车不算进去
                                    sb.Remove(sb.Length - 2, 2); //去掉\r\n(回车)
                                    iSmallLevel = 0;
                                    bIntoDouble = false;
                                }
                            }
                            else if (bBody) //语句处理
                            {
                                if (iCurrent == ResolveConfig.Flag && !bFindFlagInBody && !bIntoDouble &&
                                    iSmallLevel == 0) //@
                                {
                                    bFindFlagInBody = true;
                                }
                                else if (iCurrent == ResolveConfig.Flag && iLast == ResolveConfig.Flag && bFindFlagInBody &&
                                         !bIntoDouble && iSmallLevel == 0) //找到@@，标志无效
                                {
                                    bFindFlagInBody = false;
                                }
                                else if (bFindFlagInBody && iCurrent == 32 && !bIntoDouble) //空格
                                {
                                    bFindFlagInBody = false;
                                }
                                else if (bFindFlagInBody && iCurrent == 10 && iLast == 13) //回车
                                {
                                    bFindFlagInBody = false;
                                }
                                else if (bFindFlagInBody && iCurrent == 34 && !bIntoDouble) //("
                                {
                                    bIntoDouble = true;
                                }
                                else if (bFindFlagInBody && iCurrent == 34 && iLast != 92 && bIntoDouble) //\")
                                {
                                    bIntoDouble = false;
                                }
                                else if (!bFindFlagInBody && iLast != ResolveConfig.Flag && iCurrent == 123 &&
                                         !bIntoDouble) //{
                                {
                                    iBigLevel++;
                                }
                                else if (!bFindFlagInBody && iLast != ResolveConfig.Flag && iCurrent == 125 &&
                                         (iLast == 32 || iLast == 10) && iBigLevel > 1) //}
                                {
                                    iBigLevel--;
                                }
                                else if (!bFindFlagInBody && iLast != ResolveConfig.Flag && iCurrent == 125 &&
                                         (iLast == 32 || iLast == 10) && iBigLevel == 1) //}
                                {
                                    bProperty = false;
                                    bSure = true;
                                    flagCode.FlagStyle = FlagStyle.Body;
                                    iFlagEnd = iPosition;
                                    iBigLevel = 0;
                                }
                            }
                            if (bSure) //确定标志
                            {
                                flagCode.Code = sb.ToString();
                                if (flagCode.FlagStyle == FlagStyle.Property)
                                {
                                    if (flagCode.Code.StartsWith(((char)ResolveConfig.Flag) + "Layout=\""))
                                    {
                                        flagCode.FlagStyle = FlagStyle.Layout;
                                    }
                                }
                                if (flagCode.FlagStyle == FlagStyle.Func)
                                {
                                    if (flagCode.Code.StartsWith(((char)ResolveConfig.Flag) + "PlaceHolder(\""))
                                    {
                                        flagCode.FlagStyle = FlagStyle.PlaceHolder;
                                    }
                                }
                                if (flagCode.FlagStyle == FlagStyle.Body)
                                {
                                    flagCode.Code += "\r\n";
                                    if (flagCode.Code.StartsWith(((char)ResolveConfig.Flag) + "using{"))
                                    {
                                        flagCode.FlagStyle = FlagStyle.Using;
                                    }
                                    else if (flagCode.Code.StartsWith(((char)ResolveConfig.Flag) + "*{"))
                                    {
                                        flagCode.FlagStyle = FlagStyle.Comment;
                                    }
                                    else if (flagCode.Code.StartsWith(((char)ResolveConfig.Flag) + "PlaceContent(\""))
                                    {
                                        flagCode.FlagStyle = FlagStyle.PlaceContent;
                                    }
                                    else if (flagCode.Code.StartsWith(((char)ResolveConfig.Flag) + "{"))
                                    {
                                        flagCode.FlagStyle = FlagStyle.Statement;
                                    }
                                }
                                sb.Remove(0, sb.Length);
                                flagCode.Start = iFlagStart;
                                flagCode.End = iFlagEnd;
                                flagCodeInFile.AddCode(flagCode);
                                flagCode = new FlagCode();
                                bFindFlag = false;
                                bSure = false;
                                bProperty = false;
                                bFunc = false;
                                bBody = false;
                            }
                        }

                        if (iCurrent <= 255)
                        {
                            iPosition++;
                        }
                        else
                        {
                            iPosition += 3;
                        }
                        iLast = iCurrent;
                    }
                } while (iLenght == dataLenght);
            }
            catch (Exception ex)
            {
                Dispose();
                throw new Exception(ex.Message);
            }
            Dispose();
            return flagCodeInFile;
        }



        /// <summary>
        /// 初始化文件读取对象
        /// </summary>
        private void InitStreamReader(Encoding encoding)
        {
            if (_streamReaderFile != null)
            {
                _streamReaderFile.Close();
            }
            _streamReaderFile = new StreamReader(Source, encoding);

            //if (_streamFile != null)
            //{
            //    _streamFile.Close();
            //}
            //_streamFile = File.Open(Source, FileMode.Open, FileAccess.Read, FileShare.Read);
            //_streamFile.Seek(3, SeekOrigin.Begin);
        }


        private static Encoding GetFileEncoding(string filePath)
        {
            //byte[] unicode = { 0xFF, 0xFE, 0x41 };
            //byte[] unicodeBig = { 0xFE, 0xFF, 0x00 };
            //byte[] utf8 = { 0xEF, 0xBB, 0xBF }; //带BOM
            Encoding reVal = Encoding.Default;
            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            BinaryReader r = new BinaryReader(fs, Encoding.Default);
            int i;
            int.TryParse(fs.Length.ToString(CultureInfo.InvariantCulture), out i);
            byte[] ss = r.ReadBytes(i);
            //if (IsUtf8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF))
            if (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF)
            {
                reVal = Encoding.UTF8;
            }
            else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
            {
                reVal = Encoding.BigEndianUnicode;
            }
            else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
            {
                reVal = Encoding.Unicode;
            }
            fs.Close();
            r.Close();
            return reVal;
        }


        ///// <summary>
        ///// 判断是否是不带 BOM 的 UTF8 格式
        ///// </summary>
        ///// <param name="data"></param>
        ///// <returns></returns>
        //private static bool IsUtf8Bytes(IEnumerable<byte> data)
        //{
        //    int charByteCounter = 1;　 //计算当前正分析的字符应还有的字节数
        //    foreach (byte b in data)
        //    {
        //        byte curByte = b; //当前分析的字节.
        //        if (charByteCounter == 1)
        //        {
        //            if (curByte >= 0x80)
        //            {
        //                //判断当前
        //                while (((curByte <<= 1) & 0x80) != 0)
        //                {
        //                    charByteCounter++;
        //                }
        //                //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X　
        //                if (charByteCounter == 1 || charByteCounter > 6)
        //                {
        //                    return false;
        //                }
        //            }
        //        }
        //        else
        //        {
        //            //若是UTF-8 此时第一位必须为1
        //            if ((curByte & 0xC0) != 0x80)
        //            {
        //                return false;
        //            }
        //            charByteCounter--;
        //        }
        //    }
        //    if (charByteCounter > 1)
        //    {
        //        throw new Exception("非预期的byte格式");
        //    }
        //    return true;
        //}



        /// <summary>
        /// 读取下一个字符
        /// </summary>
        /// <returns></returns>
        private int ReadNext(char[] data)
        {
            //return _streamFile.Read(data, 0, data.Length);

            return _streamReaderFile.Read(data, 0, data.Length);
        }

        /// <summary>
        /// 关闭资源
        /// </summary>
        private void Dispose()
        {
            //if (_streamFile != null)
            //{
            //    _streamFile.Close();
            //}
            if (_streamReaderFile != null)
            {
                _streamReaderFile.Close();
            }
        }
    }
}
